#pragma once
#include "CGIVulkanResource.h"
#include "CGIVulkan.h"
#include "CGIVulkanCommandBuffer.h"
#include "CGIVulkanContext.h"
#include "CGIVulkanBarriers.h"
namespace Alice{
	VkImageAspectFlags GetAspectMaskFromUEFormat(EPixelFormat Format, bool bIncludeStencil, bool bIncludeDepth)
	{
		switch (Format)
		{
		case EPixelFormat::PF_X24_G8:
			return VK_IMAGE_ASPECT_STENCIL_BIT;
		case EPixelFormat::PF_DepthStencil:
			return (bIncludeDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (bIncludeStencil ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
		case EPixelFormat::PF_ShadowDepth:
		case EPixelFormat::PF_D24:
			return VK_IMAGE_ASPECT_DEPTH_BIT;
		default:
			return VK_IMAGE_ASPECT_COLOR_BIT;
		}
	}
	VkImageUsageFlags GetUsageFlagsFromCreateFlags(CGIVulkanDevice& InDevice, const ETextureCreateFlags& UEFlags)
	{
		VkImageUsageFlags UsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;

		if (EnumHasAnyFlags(UEFlags, ETextureCreateFlags::Presentable))
		{
			UsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
		}
		else if (EnumHasAnyFlags(UEFlags, ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::DepthStencilTargetable))
		{
			if (EnumHasAllFlags(UEFlags, ETextureCreateFlags::InputAttachmentRead))
			{
				UsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
			}
			UsageFlags |= (EnumHasAnyFlags(UEFlags, ETextureCreateFlags::RenderTargetable) ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
			if (EnumHasAllFlags(UEFlags, ETextureCreateFlags::Memoryless))
			{
				UsageFlags |= VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
				// Remove the transfer and sampled bits, as they are incompatible with the transient bit.
				UsageFlags &= ~(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
			}
		}
		else if (EnumHasAnyFlags(UEFlags, ETextureCreateFlags::DepthStencilResolveTarget))
		{
			UsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
		}
		else if (EnumHasAnyFlags(UEFlags, ETextureCreateFlags::ResolveTargetable))
		{
			UsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
		}

		if (EnumHasAnyFlags(UEFlags, ETextureCreateFlags::UAV))
		{
			UsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
		}

		return UsageFlags;
	}
	static VkImageLayout GetInitialLayoutFromRHIAccess(CGIAccess RHIAccess, bool bIsDepthStencilTarget, bool bSupportReadOnlyOptimal)
	{
		if (EnumHasAnyFlags(RHIAccess, CGIAccess::RTV) || RHIAccess == CGIAccess::Present)
		{
			return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
		}

		if (EnumHasAnyFlags(RHIAccess, CGIAccess::DSVWrite))
		{
			return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
		}

		if (EnumHasAnyFlags(RHIAccess, CGIAccess::DSVRead))
		{
			return VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL;
		}

		if (EnumHasAnyFlags(RHIAccess, CGIAccess::SRVMask))
		{
			if (bIsDepthStencilTarget)
			{
				return VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL;
			}

			return bSupportReadOnlyOptimal ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
		}

		if (EnumHasAnyFlags(RHIAccess, CGIAccess::UAVMask))
		{
			return VK_IMAGE_LAYOUT_GENERAL;
		}

		switch (RHIAccess)
		{
		case CGIAccess::Unknown:	return VK_IMAGE_LAYOUT_UNDEFINED;
		case CGIAccess::Discard:	return VK_IMAGE_LAYOUT_UNDEFINED;
		case CGIAccess::CopySrc:	return VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
		case CGIAccess::CopyDest:	return VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
		}

		return VK_IMAGE_LAYOUT_UNDEFINED;
	}
	VkFormat UEToVkTextureFormat(EPixelFormat UEFormat, const bool bIsSRGB)
	{
		if (bIsSRGB)
		{
			return GVulkanSRGBFormat[(uint32)UEFormat];
		}
		else
		{
			return (VkFormat)GPixelFormats[(uint32)UEFormat].PlatformFormat;
		}
	}
	VkImageViewType UETextureDimensionToVkImageViewType(ETextureDimension Dimension)
	{
		switch (Dimension)
		{
		case ETextureDimension::Texture2D: return VK_IMAGE_VIEW_TYPE_2D;
		case ETextureDimension::Texture2DArray: return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
		case ETextureDimension::Texture3D: return VK_IMAGE_VIEW_TYPE_3D;
		case ETextureDimension::TextureCube: return VK_IMAGE_VIEW_TYPE_CUBE;
		case ETextureDimension::TextureCubeArray: return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
		default: return VK_IMAGE_VIEW_TYPE_MAX_ENUM;
		}
	}
	VulkanRenderTargetLayout::VulkanRenderTargetLayout(CGIVulkanDevice& InDevice, const CGIRenderPassInfo* RPInfo, VkImageLayout CurrentDepthLayout, VkImageLayout CurrentStencilLayout)
		: NumAttachmentDescriptions(0)
		, NumColorAttachments(0)
		, bHasDepthStencil(false)
		, NumUsedClearValues(0)
	{
		//ResetAttachments();
		/*FRenderPassCompatibleHashableStruct CompatibleHashInfo;
		FRenderPassFullHashableStruct FullHashInfo;

		bool bSetExtent = false;
		bool bFoundClearOp = false;
		bool bMultiviewRenderTargets = false;

		int32 NumColorRenderTargets = RPInfo->GetNumColorRenderTargets();
		for (int32 Index = 0; Index < NumColorRenderTargets; ++Index)
		{
			const CGIRenderPassInfo::FColorEntry& ColorEntry = RPInfo.ColorRenderTargets[Index];
			CGIVulkanTexture* Texture = ResourceCast(ColorEntry.RenderTarget);
			const FRHITextureDesc& TextureDesc = Texture->GetDesc();

			if (bSetExtent)
			{
				ensure(Extent.Extent3D.width == FMath::Max(1, TextureDesc.Extent.X >> ColorEntry.MipIndex));
				ensure(Extent.Extent3D.height == FMath::Max(1, TextureDesc.Extent.Y >> ColorEntry.MipIndex));
				ensure(Extent.Extent3D.depth == TextureDesc.Depth);
			}
			else
			{
				bSetExtent = true;
				Extent.Extent3D.width = FMath::Max(1, TextureDesc.Extent.X >> ColorEntry.MipIndex);
				Extent.Extent3D.height = FMath::Max(1, TextureDesc.Extent.Y >> ColorEntry.MipIndex);
				Extent.Extent3D.depth = TextureDesc.Depth;
			}

			// CustomResolveSubpass can have targets with a different NumSamples
			//ensure(!NumSamples || NumSamples == ColorEntry.RenderTarget->GetNumSamples() || RPInfo.SubpassHint == ESubpassHint::CustomResolveSubpass);
			//NumSamples = ColorEntry.RenderTarget->GetNumSamples();

			//ensure(!GetIsMultiView() || !bMultiviewRenderTargets || Texture->GetNumberOfArrayLevels() > 1);
			//bMultiviewRenderTargets = Texture->GetNumberOfArrayLevels() > 1;
			// With a CustomResolveSubpass last color attachment is a resolve target
			bool bCustomResolveAttachment = (Index == (NumColorRenderTargets - 1)) && RPInfo.SubpassHint == ESubpassHint::CustomResolveSubpass;

			VkAttachmentDescription& CurrDesc = Desc[NumAttachmentDescriptions];
			CurrDesc.samples = bCustomResolveAttachment ? VK_SAMPLE_COUNT_1_BIT : static_cast<VkSampleCountFlagBits>(NumSamples);
			CurrDesc.format = UEToVkTextureFormat(ColorEntry.RenderTarget->GetFormat(), EnumHasAllFlags(Texture->GetDesc().Flags, TexCreate_SRGB));
			CurrDesc.loadOp = RenderTargetLoadActionToVulkan(GetLoadAction(ColorEntry.Action));
			bFoundClearOp = bFoundClearOp || (CurrDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);
			CurrDesc.storeOp = RenderTargetStoreActionToVulkan(GetStoreAction(ColorEntry.Action));
			CurrDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
			CurrDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;

			if (EnumHasAnyFlags(Texture->GetDesc().Flags,  ETextureCreateFlags::Memoryless))
			{
				//ensure(CurrDesc.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
			}

			// If the initial != final we need to change the FullHashInfo and use FinalLayout
			CurrDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
			CurrDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

			ColorReferences[NumColorAttachments].attachment = NumAttachmentDescriptions;
			ColorReferences[NumColorAttachments].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;

			if (CurrDesc.samples > VK_SAMPLE_COUNT_1_BIT && ColorEntry.ResolveTarget)
			{
				Desc[NumAttachmentDescriptions + 1] = Desc[NumAttachmentDescriptions];
				Desc[NumAttachmentDescriptions + 1].samples = VK_SAMPLE_COUNT_1_BIT;
				Desc[NumAttachmentDescriptions + 1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
				Desc[NumAttachmentDescriptions + 1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
				//ResolveReferences[NumColorAttachments].attachment = NumAttachmentDescriptions + 1;
				//ResolveReferences[NumColorAttachments].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
				CompatibleHashInfo.AttachmentsToResolve |= (uint16)(1 << NumColorAttachments);
				++NumAttachmentDescriptions;
				//bHasResolveAttachments = true;
			}

			CompatibleHashInfo.Formats[NumColorAttachments] = CurrDesc.format;
			FullHashInfo.LoadOps[NumColorAttachments] = CurrDesc.loadOp;
			FullHashInfo.InitialLayout[NumColorAttachments] = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
			FullHashInfo.StoreOps[NumColorAttachments] = CurrDesc.storeOp;
			++CompatibleHashInfo.NumAttachments;

			++NumAttachmentDescriptions;
			++NumColorAttachments;
		}
		bool bMultiViewDepthStencil = false;
		if (RPInfo.DepthStencilRenderTarget.DepthStencilTarget)
		{
			VkAttachmentDescription& CurrDesc = Desc[NumAttachmentDescriptions];
			FMemory::Memzero(CurrDesc);
			FVulkanTexture* Texture = ResourceCast(RPInfo.DepthStencilRenderTarget.DepthStencilTarget);
			check(Texture);
			const FRHITextureDesc& TextureDesc = Texture->GetDesc();
			bMultiViewDepthStencil = (Texture->GetNumberOfArrayLevels() > 1) && !Texture->GetDesc().IsTextureCube();
			CurrDesc.samples = static_cast<VkSampleCountFlagBits>(RPInfo.DepthStencilRenderTarget.DepthStencilTarget->GetNumSamples());
			// CustomResolveSubpass can have targets with a different NumSamples
			ensure(!NumSamples || CurrDesc.samples == NumSamples || RPInfo.SubpassHint == ESubpassHint::CustomResolveSubpass);
			NumSamples = CurrDesc.samples;
			CurrDesc.format = UEToVkTextureFormat(RPInfo.DepthStencilRenderTarget.DepthStencilTarget->GetFormat(), false);
			CurrDesc.loadOp = RenderTargetLoadActionToVulkan(GetLoadAction(GetDepthActions(RPInfo.DepthStencilRenderTarget.Action)));
			CurrDesc.stencilLoadOp = RenderTargetLoadActionToVulkan(GetLoadAction(GetStencilActions(RPInfo.DepthStencilRenderTarget.Action)));
			bFoundClearOp = bFoundClearOp || (CurrDesc.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR || CurrDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR);

			CurrDesc.storeOp = RenderTargetStoreActionToVulkan(GetStoreAction(GetDepthActions(RPInfo.DepthStencilRenderTarget.Action)));
			CurrDesc.stencilStoreOp = RenderTargetStoreActionToVulkan(GetStoreAction(GetStencilActions(RPInfo.DepthStencilRenderTarget.Action)));

			if (EnumHasAnyFlags(TextureDesc.Flags, TexCreate_Memoryless))
			{
				ensure(CurrDesc.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
				ensure(CurrDesc.stencilStoreOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
			}

			FExclusiveDepthStencil ExclusiveDepthStencil = RPInfo.DepthStencilRenderTarget.ExclusiveDepthStencil;
			if (FVulkanPlatform::RequiresDepthWriteOnStencilClear() &&
				RPInfo.DepthStencilRenderTarget.Action == EDepthStencilTargetActions::LoadDepthClearStencil_StoreDepthStencil)
			{
				ExclusiveDepthStencil = FExclusiveDepthStencil::DepthWrite_StencilWrite;
				CurrentDepthLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
				CurrentStencilLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
			}

			// If the initial != final we need to change the FullHashInfo and use FinalLayout
			CurrDesc.initialLayout = CurrentDepthLayout;
			CurrDesc.finalLayout = CurrentDepthLayout;
			StencilDesc.stencilInitialLayout = CurrentStencilLayout;
			StencilDesc.stencilFinalLayout = CurrentStencilLayout;

			// We can't have the final layout be UNDEFINED, but it's possible that we get here from a transient texture
			// where the stencil was never used yet.  We can set the layout to whatever we want, the next transition will
			// happen from UNDEFINED anyhow.
			if (CurrentDepthLayout == VK_IMAGE_LAYOUT_UNDEFINED)
			{
				// Unused image aspects with a LoadOp but undefined layout should just remain untouched
				if (!RPInfo.DepthStencilRenderTarget.ExclusiveDepthStencil.IsUsingDepth() &&
					InDevice.GetOptionalExtensions().HasEXTLoadStoreOpNone &&
					(CurrDesc.loadOp == VK_ATTACHMENT_LOAD_OP_LOAD))
				{
					CurrDesc.loadOp = VK_ATTACHMENT_LOAD_OP_NONE_KHR;
				}

				check(CurrDesc.storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
				CurrDesc.finalLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
			}
			if (CurrentStencilLayout == VK_IMAGE_LAYOUT_UNDEFINED)
			{
				// Unused image aspects with a LoadOp but undefined layout should just remain untouched
				if (!RPInfo.DepthStencilRenderTarget.ExclusiveDepthStencil.IsUsingStencil() &&
					InDevice.GetOptionalExtensions().HasEXTLoadStoreOpNone &&
					(CurrDesc.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD))
				{
					CurrDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_NONE_KHR;
				}

				check(CurrDesc.stencilStoreOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
				StencilDesc.stencilFinalLayout = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL;
			}

			DepthReference.attachment = NumAttachmentDescriptions;
			DepthReference.layout = CurrentDepthLayout;
			StencilReference.stencilLayout = CurrentStencilLayout;

			if (GRHISupportsDepthStencilResolve && CurrDesc.samples > VK_SAMPLE_COUNT_1_BIT && RPInfo.DepthStencilRenderTarget.ResolveTarget)
			{
				Desc[NumAttachmentDescriptions + 1] = Desc[NumAttachmentDescriptions];
				Desc[NumAttachmentDescriptions + 1].samples = VK_SAMPLE_COUNT_1_BIT;
				Desc[NumAttachmentDescriptions + 1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
				Desc[NumAttachmentDescriptions + 1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
				Desc[NumAttachmentDescriptions + 1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
				Desc[NumAttachmentDescriptions + 1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
				DepthStencilResolveReference.attachment = NumAttachmentDescriptions + 1;
				DepthStencilResolveReference.layout = CurrentDepthLayout;
				// NumColorAttachments was incremented after the last color attachment
				ensureMsgf(NumColorAttachments < 16, TEXT("Must have room for depth resolve bit"));
				CompatibleHashInfo.AttachmentsToResolve |= (uint16)(1 << NumColorAttachments);
				++NumAttachmentDescriptions;
				bHasDepthStencilResolve = true;
			}

			FullHashInfo.LoadOps[MaxSimultaneousRenderTargets] = CurrDesc.loadOp;
			FullHashInfo.LoadOps[MaxSimultaneousRenderTargets + 1] = CurrDesc.stencilLoadOp;
			FullHashInfo.StoreOps[MaxSimultaneousRenderTargets] = CurrDesc.storeOp;
			FullHashInfo.StoreOps[MaxSimultaneousRenderTargets + 1] = CurrDesc.stencilStoreOp;
			FullHashInfo.InitialLayout[MaxSimultaneousRenderTargets] = CurrentDepthLayout;
			FullHashInfo.InitialLayout[MaxSimultaneousRenderTargets + 1] = CurrentStencilLayout;
			CompatibleHashInfo.Formats[MaxSimultaneousRenderTargets] = CurrDesc.format;

			++NumAttachmentDescriptions;

			bHasDepthStencil = true;

			if (bSetExtent)
			{
				// Depth can be greater or equal to color. Clamp to the smaller size.
				Extent.Extent3D.width = FMath::Min<uint32>(Extent.Extent3D.width, TextureDesc.Extent.X);
				Extent.Extent3D.height = FMath::Min<uint32>(Extent.Extent3D.height, TextureDesc.Extent.Y);
			}
			else
			{
				bSetExtent = true;
				Extent.Extent3D.width = TextureDesc.Extent.X;
				Extent.Extent3D.height = TextureDesc.Extent.Y;
				Extent.Extent3D.depth = TextureDesc.Depth;
			}
		}
		else if (NumColorRenderTargets == 0)
		{
			// No Depth and no color, it's a raster-only pass so make sure the renderArea will be set up properly
			//checkf(RPInfo.ResolveRect.IsValid(), TEXT("For raster-only passes without render targets, ResolveRect has to contain the render area"));
			bSetExtent = true;
			Offset.Offset3D.x = RPInfo.ResolveRect.X1;
			Offset.Offset3D.y = RPInfo.ResolveRect.Y1;
			Offset.Offset3D.z = 0;
			Extent.Extent3D.width = RPInfo.ResolveRect.X2 - RPInfo.ResolveRect.X1;
			Extent.Extent3D.height = RPInfo.ResolveRect.Y2 - RPInfo.ResolveRect.Y1;
			Extent.Extent3D.depth = 1;
		}
		
		SubpassHint = RPInfo.SubpassHint;
		CompatibleHashInfo.SubpassHint = (uint8)RPInfo.SubpassHint;

		CompatibleHashInfo.NumSamples = NumSamples;
		CompatibleHashInfo.MultiViewCount = MultiViewCount;
		
		RenderPassCompatibleHash = FCrc::MemCrc32(&CompatibleHashInfo, sizeof(CompatibleHashInfo));
		RenderPassFullHash = FCrc::MemCrc32(&FullHashInfo, sizeof(FullHashInfo), RenderPassCompatibleHash);
		NumUsedClearValues = bFoundClearOp ? NumAttachmentDescriptions : 0;
		bCalculatedHash = true;*/
	}
    CGIVulkanTexture::CGIVulkanTexture()
        :CGITexture(ECGIResourceType::RRT_Texture)
    {

    }
    CGIVulkanTexture::CGIVulkanTexture(CGIVulkanDevice& InDevice, const CGITextureCreateDesc& InCreateDesc, VkImage InImage, const CGIVulkanRHIExternalImageDeleteCallbackInfo& InExternalImageDeleteCallbackInfo)
	:CGITexture(InCreateDesc)
	, mImage(InImage)
	, mStorageFormat(VK_FORMAT_UNDEFINED)
	, mViewFormat(VK_FORMAT_UNDEFINED)
	, mTiling(VK_IMAGE_TILING_MAX_ENUM)
    {
		mStorageFormat = UEToVkTextureFormat(InCreateDesc.Format, false);
		mViewFormat = UEToVkTextureFormat(InCreateDesc.Format, EnumHasAllFlags(InCreateDesc.Flags,  ETextureCreateFlags::SRGB));
		mFullAspectMask = GetAspectMaskFromUEFormat(InCreateDesc.Format, true, true);
		mPartialAspectMask = GetAspectMaskFromUEFormat(InCreateDesc.Format, false, true);
		if (EnumHasAllFlags(InCreateDesc.Flags, ETextureCreateFlags::Presentable) && mTiling == VK_IMAGE_TILING_MAX_ENUM)
		{
			mTiling = VK_IMAGE_TILING_OPTIMAL;
		}
		if (mImage != VK_NULL_HANDLE)
		{
			mImageUsageFlags = GetUsageFlagsFromCreateFlags(InDevice, InCreateDesc.Flags);

			const bool bRenderTarget = EnumHasAnyFlags(InCreateDesc.Flags, ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::DepthStencilTargetable);
			const VkImageLayout InitialLayout = GetInitialLayoutFromRHIAccess(InCreateDesc.InitialState, bRenderTarget && IsDepthOrStencilAspect(), SupportsSampling());
			const bool bDoInitialClear = bRenderTarget;
			const bool bOnlyAddToLayoutManager = !bRenderTarget;

			mDefaultLayout = InitialLayout;

			if (true)//!IsInRenderingThread() || (RHICmdList.Bypass() || !IsRunningRHIInSeparateThread()))
			{
				CGIVulkanCommandListContext& Context = InDevice.GetImmediateContext();
				if (false)//bOnlyAddToLayoutManager)
				{
					//CGIVulkanCmdBuffer* CmdBuffer = Context.GetCommandBufferManager()->GetActiveCmdBuffer();
					//CmdBuffer->GetLayoutManager().SetFullLayout(*this, InitialLayout, true);
				}
				else if (InitialLayout != VK_IMAGE_LAYOUT_UNDEFINED || bDoInitialClear)
				{
					SetInitialImageState(Context, InitialLayout, bDoInitialClear, InCreateDesc.ClearValue, false);
				}
			}
			else
			{
				//ALLOC_COMMAND_CL(RHICmdList, FRHICommandSetInitialImageState)(this, InitialLayout, bOnlyAddToLayoutManager, bDoInitialClear, InCreateDesc.ClearValue, false);
			}
		}
    }
	void CGIVulkanTexture::SetInitialImageState(CGIVulkanCommandListContext& Context, VkImageLayout InitialLayout, bool bClear, const FClearValueBinding& ClearValueBinding, bool bIsTransientResource)
	{
		// Can't use TransferQueue as Vulkan requires that queue to also have Gfx or Compute capabilities...
		//#todo-rco: This function is only used during loading currently, if used for regular RHIClear then use the ActiveCmdBuffer
		// NOTE: Transient resources' memory might have belonged to another resource earlier in the ActiveCmdBuffer, so we can't use UploadCmdBuffer
		CGIVulkanCommandBuffer* CmdBuffer = Context.GetCommandBufferManager()->GetUploadCmdBuffer();//bIsTransientResource ? Context.GetCommandBufferManager()->GetActiveCmdBuffer() : Context.GetCommandBufferManager()->GetUploadCmdBuffer();

		VkImageSubresourceRange SubresourceRange = CGIVulkanPipelineBarrier::MakeSubresourceRange(mFullAspectMask);

		VkImageLayout CurrentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
		if (bClear && !bIsTransientResource)
		{
			{
				CGIVulkanPipelineBarrier Barrier;
				Barrier.AddImageLayoutTransition(mImage, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, SubresourceRange);
				Barrier.Execute(CmdBuffer);
			}

			if (mFullAspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
			{
				VkClearColorValue Color={};
				Color.float32[0] = ClearValueBinding.Value.Color[0];
				Color.float32[1] = ClearValueBinding.Value.Color[1];
				Color.float32[2] = ClearValueBinding.Value.Color[2];
				Color.float32[3] = ClearValueBinding.Value.Color[3];

				vkCmdClearColorImage(CmdBuffer->GetHandle(), mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &Color, 1, &SubresourceRange);
			}
			else
			{
				VkClearDepthStencilValue Value={};
				Value.depth = ClearValueBinding.Value.DSValue.Depth;
				Value.stencil = ClearValueBinding.Value.DSValue.Stencil;

				vkCmdClearDepthStencilImage(CmdBuffer->GetHandle(), mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &Value, 1, &SubresourceRange);
			}

			CurrentLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
		}

		if ((InitialLayout != CurrentLayout) && (InitialLayout != VK_IMAGE_LAYOUT_UNDEFINED))
		{
			//CGIVulkanPipelineBarrier Barrier;
			//Barrier.AddFullImageLayoutTransition(*this, CurrentLayout, InitialLayout);
			//Barrier.Execute(CmdBuffer);
		}

		CmdBuffer->GetLayoutManager().SetFullLayout(*this, InitialLayout);
	}
    CGIVulkanView::CGIVulkanView(CGIVulkanDevice& InDevice, VkDescriptorType InDescriptorType)
    : mDevice(InDevice)
    {
        //BindlessHandle = Device.GetBindlessDescriptorManager()->ReserveDescriptor(InDescriptorType);
    }
    CGIVulkanView* CGIVulkanView::InitAsTextureView(
		  VkImage InImage
		, VkImageViewType ViewType
		, VkImageAspectFlags AspectFlags
		, EPixelFormat UEFormat
		, VkFormat Format
		, uint32 FirstMip
		, uint32 NumMips
		, uint32 ArraySliceIndex
		, uint32 NumArraySlices
		, bool bUseIdentitySwizzle
		, VkImageUsageFlags ImageUsageFlags
		, VkSamplerYcbcrConversion SamplerYcbcrConversion)
	{
		// We will need a deferred update if the descriptor was already in use
		//const bool bImmediateUpdate = !IsInitialized();

		//check(GetViewType() == EType::Null);
		////Storage.Emplace<FTextureView>();
		//FTextureView& TV = Storage.Get<FTextureView>();

		//LLM_SCOPE_VULKAN(ELLMTagVulkan::VulkanTextures);

		VkImageViewCreateInfo ViewInfo={};
		ViewInfo.sType=VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
		ViewInfo.image = InImage;
		ViewInfo.viewType = ViewType;
		ViewInfo.format = Format;

		if (bUseIdentitySwizzle)
		{
			ViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
			ViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
			ViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
			ViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
		}
		else
		{
			//ViewInfo.components = mDevice.GetFormatComponentMapping(UEFormat);
		}

		ViewInfo.subresourceRange.aspectMask = AspectFlags;
		ViewInfo.subresourceRange.baseMipLevel = FirstMip;
		ViewInfo.subresourceRange.levelCount = NumMips;
		ViewInfo.subresourceRange.baseArrayLayer = ArraySliceIndex;
		ViewInfo.subresourceRange.layerCount = NumArraySlices;

		//HACK.  DX11 on PC currently uses a D24S8 depthbuffer and so needs an X24_G8 SRV to visualize stencil.
		//So take that as our cue to visualize stencil.  In the future, the platform independent code will have a real format
		//instead of PF_DepthStencil, so the cross-platform code could figure out the proper format to pass in for this.
		if (UEFormat == EPixelFormat::PF_X24_G8)
		{
			ViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
		}

		// Inform the driver the view will only be used with a subset of usage flags (to help performance and/or compatibility)
		VkImageViewUsageCreateInfo ImageViewUsageCreateInfo;
		if (ImageUsageFlags != 0)
		{
			ImageViewUsageCreateInfo={};
			ImageViewUsageCreateInfo.sType=VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
			ImageViewUsageCreateInfo.usage = ImageUsageFlags;

			ImageViewUsageCreateInfo.pNext = (void*)ViewInfo.pNext;
			ViewInfo.pNext = &ImageViewUsageCreateInfo;
		}

		//INC_DWORD_STAT(STAT_VulkanNumImageViews);
		vkCreateImageView(mDevice.GetDevice(), &ViewInfo, NULL, &mTextureView.View);

		mTextureView.Image = InImage;

		/*if (UseVulkanDescriptorCache())
		{
			TV.ViewId = ++GVulkanImageViewHandleIdCounter;
		}*/

		//const bool bDepthOrStencilAspect = (AspectFlags & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0;
		//mDevice.GetBindlessDescriptorManager()->UpdateImage(BindlessHandle, TV.View, bDepthOrStencilAspect, bImmediateUpdate);

		return this;
	}
}